package nl.altenpts.net.kad;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Date;

public class Node implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public Node(PublicKey pubkey, InetSocketAddress address) {
		this.pubkey = pubkey;
		this.address = address;
		this.id = Kademlia.pubkeyToId(pubkey);
		lastseen = 0;	
	}
	
	public Node(ByteBuffer buffer) throws InvalidKeySpecException, UnknownHostException {
		byte[] enckey = new byte[buffer.getInt()];
		buffer.get(enckey);
		pubkey = Kademlia.enckeyToPublicKey(enckey);
		
		byte[] iphost = new byte[buffer.getInt()];
		buffer.get(iphost);
		int port = buffer.getInt();
		this.address = new InetSocketAddress(InetAddress.getByAddress(iphost), port);
		this.id = Kademlia.pubkeyToId(pubkey);
		lastseen = 0;
	}
	
	public ByteBuffer toByteBuffer() {
		byte[] pubkey = this.pubkey.getEncoded();
		byte[] ipaddr = address.getAddress().getAddress();

		ByteBuffer buffer = ByteBuffer.allocate(4 + pubkey.length + 4 + ipaddr.length + 4);
		buffer.putInt(pubkey.length);
		buffer.put(pubkey);
		buffer.putInt(ipaddr.length);
		buffer.put(ipaddr);
		buffer.putInt(address.getPort());
		buffer.flip();
		
		return buffer;
	}
	
	public Id getId() {
		return id;
	}
	
	public void updateLastSeen() {
		Date d = new Date();		
		lastseen = d.getTime();		
	}
	
	public void updateLastSeen(long when) {
		lastseen = when;
	}
	
	public long getLastSeen() {
		return lastseen;
	}
	
	public boolean equals(Object o) {
		Node other = (Node) o;
		
		return pubkey.equals(other.pubkey);
				
	}
	
	public void update(Node n) {
		assert this.equals(n);
		
		address = n.address;
		lastseen = n.lastseen;		
	}
	
	public boolean checkId() {
		try {
			MessageDigest md = MessageDigest.getInstance(Kademlia.mdalg);			
			Id keyid = new Id(md.digest(pubkey.getEncoded()));
			return keyid.equals(id);
		} catch (NoSuchAlgorithmException e) {
			assert(false);
			return false;
		}		
	}
	
	public InetSocketAddress getAddress() {
		return address;
	}
	
	public PublicKey getPublicKey() {
		return pubkey;
	}
	
	private Id id;
	private PublicKey pubkey;
	private InetSocketAddress address;
	private long lastseen;
}
